package cn.iocoder.yudao.module.design.service.flowtask;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.design.annotation.NodeAction;
import cn.iocoder.yudao.module.design.controller.admin.flowtask.vo.*;
import cn.iocoder.yudao.module.design.convert.flowtask.FlowTaskConvert;
import cn.iocoder.yudao.module.design.dal.dataobject.flow.FlowDO;
import cn.iocoder.yudao.module.design.dal.dataobject.flowtask.FlowTaskCountDO;
import cn.iocoder.yudao.module.design.dal.dataobject.flowtask.FlowTaskDO;
import cn.iocoder.yudao.module.design.dal.dataobject.flowtaskaction.FlowTaskActionDO;
import cn.iocoder.yudao.module.design.dal.dataobject.house.HouseDO;
import cn.iocoder.yudao.module.design.dal.dataobject.houseUserRel.HouseUserRelDO;
import cn.iocoder.yudao.module.design.dal.dataobject.node.NodeDO;
import cn.iocoder.yudao.module.design.dal.dataobject.pic.PicDO;
import cn.iocoder.yudao.module.design.dal.mysql.flow.FlowMapper;
import cn.iocoder.yudao.module.design.dal.mysql.flowtask.FlowTaskMapper;
import cn.iocoder.yudao.module.design.dal.mysql.flowtaskaction.FlowTaskActionMapper;
import cn.iocoder.yudao.module.design.dal.mysql.house.HouseMapper;
import cn.iocoder.yudao.module.design.dal.mysql.houseUserRel.HouseUserRelMapper;
import cn.iocoder.yudao.module.design.dal.mysql.node.NodeMapper;
import cn.iocoder.yudao.module.design.dal.mysql.pic.PicMapper;
import cn.iocoder.yudao.module.design.service.pic.PicService;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.design.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.design.enums.design.*;
import cn.iocoder.yudao.module.design.enums.user.DesignUserRoleEnum;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.design.enums.ErrorCodeConstants.FLOW_TASK_NOT_EXISTS;

/**
 * 待办任务 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class FlowTaskServiceImpl implements FlowTaskService {

    @Resource
    private FlowTaskMapper flowTaskMapper;
    @Resource
    private HouseMapper houseMapper;
    @Resource
    private NodeMapper nodeMapper;

    @Resource
    private FlowMapper flowMapper;

    @Resource
    private HouseUserRelMapper houseUserRelMapper;

    @Resource
    private PicMapper picMapper;

    @Resource
    private FlowTaskActionMapper flowTaskActionMapper;

    @Resource
    private PicService picService;

    @Resource
    private AdminUserService userService;


    @Override
    public Long createFlowTask(FlowTaskCreateReqVO createReqVO) {
        // 插入
        FlowTaskDO flowTask = FlowTaskConvert.INSTANCE.convert(createReqVO);
        // 进行中
        flowTask.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_1.getCode());
        // 消息通知
//        flowTask.setTaskType("3");
        flowTask.setDeleted(false);
        flowTaskMapper.insert(flowTask);
        // 返回
        PicDO picDo = new PicDO();
        picDo.setHouseId(flowTask.getHouseId());
        picDo.setItemId(flowTask.getId());
        picDo.setUploadType("0");
        picDo.setSourceType("5");
        // 保存图片文件
        picService.savePicData(picDo,createReqVO.getFileList());
        // 保存附件
        picDo.setUploadType("1");
        picService.savePicData(picDo,createReqVO.getDocList());
        return flowTask.getId();
    }

    @Override
    public void updateFlowTask(FlowTaskUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateFlowTaskExists(updateReqVO.getId());
        // 更新
        FlowTaskDO updateObj = FlowTaskConvert.INSTANCE.convert(updateReqVO);
        flowTaskMapper.updateById(updateObj);
    }

    @Override
    public void updateFlowTaskDealerId(Long houseId,Long oldUserId,Long newUserId) {
        QueryWrapper<FlowTaskDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("house_id",houseId);
        queryWrapper.eq("dealer_id",oldUserId);
        FlowTaskDO  flowDO = new FlowTaskDO();
        flowDO.setDealerId(newUserId);
        // 更新
        flowTaskMapper.update(flowDO,queryWrapper);
    }
    @Override
    public void deleteFlowTask(Long id) {
        // 校验存在
        this.validateFlowTaskExists(id);
        // 删除
        flowTaskMapper.deleteById(id);
    }

    private void validateFlowTaskExists(Long id) {
        if (flowTaskMapper.selectById(id) == null) {
            throw exception(FLOW_TASK_NOT_EXISTS);
        }
    }

    @Override
    public FlowTaskDO getFlowTask(Long id) {
        return flowTaskMapper.selectById(id);
    }

    /**
     * 获得待办任务
     *
     * @param id 编号
     * @return 待办任务
     */
    @Override
    public FlowTaskDO getFlowTaskByNodeId(Long id) {
        // 最终任务项
        NodeDO nextTaskNodeDo = new NodeDO();
        // 根据nodeId flowCd   statusCd 查询出当前任务所属id
        NodeDO nodeDO = nodeMapper.selectById(id);
        FlowDO flowDO = flowMapper.selectById(nodeDO.getFlowId());
        QueryWrapper<FlowTaskDO> queryWrapper = new QueryWrapper<FlowTaskDO>();

        // 查询当前任务明细
        queryWrapper.eq("flow_cd",flowDO.getFlowCd());
//        queryWrapper.eq("status_cd","1");
        queryWrapper.eq("node_id",id);
        return flowTaskMapper.selectOne(queryWrapper);
    }


    @Override
    public List<FlowTaskDO> getFlowTaskList(Collection<Long> ids) {
        return flowTaskMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<FlowTaskDO> getFlowTaskPage(FlowTaskPageReqVO pageReqVO) {
        pageReqVO.setDealerId(SecurityFrameworkUtils.getLoginUserId());
        // 进行中
        if(ObjectUtil.isEmpty(pageReqVO.getStatusCd())){
            pageReqVO.setStatusCd("1");
        }


        return  flowTaskMapper.selectPage(pageReqVO);
    }

    @Override
    public List<FlowTaskDO> getFlowTaskList(FlowTaskExportReqVO exportReqVO) {
        return flowTaskMapper.selectList(exportReqVO);
    }

    @Override
    public List<FlowTaskDO> getFlowTaskList(FlowTaskBaseVO vo) {
        vo.setDealerId(SecurityFrameworkUtils.getLoginUserId());
        // 进行中
        if(ObjectUtil.isEmpty(vo.getStatusCd())){
            vo.setStatusCd("1");
        }

        return flowTaskMapper.selectList(vo);
    }

    /**
     * 流转待办任务
     *
     * @param id
     */
    @Override
    public void submitFlowTaskList(Long id) {
/*      -A
            -- A1
            -- A2
        -B
            -- B1
                -- B11
                -- B12
            -- B2
                -- B21
                -- B22
       -C
            -- C1
                -- C11
                    -- C111
                    -- C112
                -- C12
                    -- C121
                    -- C122
            -- C2
                -- C21
                    -- C211
                    -- C212
                -- C22
                    -- C221
                    -- C222
*/
        // 最终任务项
        NodeDO nextTaskNodeDo = new NodeDO();
        // 查询当前任务明细
        FlowTaskDO flowTaskDO = flowTaskMapper.selectById(id);
        pushFlowTask(flowTaskDO);


    }

    /**
     * 流转待办任务
     *
     * @param flowTaskCustomizeVo           编号
     * @return 待办任务列表
     */
    @Override
    @NodeAction(test = "#{flowTaskCustomizeVo.methodName}")
    public void submitFlowTaskListByNodeId(FlowTaskCustomizeVo flowTaskCustomizeVo) {
        // 最终任务项
        NodeDO nextTaskNodeDo = new NodeDO();
        // 根据nodeId flowCd   statusCd 查询出当前任务所属id
        NodeDO nodeDO = nodeMapper.selectById(flowTaskCustomizeVo.getNodeId());
        if(!NodeStatusEnum.NODE_STATUS_ENUM_1.getCode().toString().equals(nodeDO.getStatusCd())){

            throw ServiceExceptionUtil.exception(ErrorCodeConstants.NODE_DATA_IS_UPDATE);
        }
        FlowDO flowDO = flowMapper.selectById(nodeDO.getFlowId());
        QueryWrapper<FlowTaskDO> queryWrapper = new QueryWrapper<FlowTaskDO>();
        // 查询当前任务明细
        queryWrapper.eq("flow_cd",flowDO.getFlowCd());
        queryWrapper.eq("status_cd","1");
        queryWrapper.eq("node_id",flowTaskCustomizeVo.getNodeId());
        FlowTaskDO flowTaskDO = flowTaskMapper.selectOne(queryWrapper);
        pushFlowTask(flowTaskDO);

    }




    /**
     * 提交当前任务，推送新任务
     * @param flowTaskDO 任务详情
     */
    @NodeAction
    public void pushFlowTask( FlowTaskDO flowTaskDO ){
        // 更新流程任务  修改当前节点状态为已完成
        getNextTaskNodeDo(flowTaskDO.getFlowCd(),flowTaskDO.getNodeId());

        // 修改当前任务状态为已完成
        flowTaskDO.setFinishTime(new Date());
        flowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_2.getCode());
        flowTaskMapper.updateById(flowTaskDO);
    }

    /**
     * 消息待办中补充任务信息
     * @param vo
     */
    @Override
    public void replenishTask(FlowTaskBaseVO vo) {
        if(vo.getNodeId()==null){
            // 最终任务项
            NodeDO nextTaskNodeDo = new NodeDO();
            // 根据nodeId flowCd   statusCd 查询出当前任务所属id
            NodeDO nodeDO = nodeMapper.selectById(vo.getId());
            FlowDO flowDO = flowMapper.selectById(vo.getFlowId());
            QueryWrapper<FlowTaskDO> queryWrapper = new QueryWrapper<FlowTaskDO>();

            // 查询当前任务明细
            queryWrapper.eq("flow_cd",flowDO.getFlowCd());
            queryWrapper.eq("status_cd","1");
            queryWrapper.eq("node_id",vo.getId());
            FlowTaskDO flowTaskDO = flowTaskMapper.selectOne(queryWrapper);
            vo.setNodeId(nodeDO.getId());
            vo.setId(flowTaskDO.getId());
        }
        replenishTaskChild(vo);


    }

    public void  replenishTaskChild(FlowTaskBaseVO vo){
        FlowTaskDO flowTaskDO = flowTaskMapper.selectById(vo.getId());
        // 将起止时间 、 处理人 图片等信息  补充到NodeDo 中
        Date startTime = vo.getStartTime();
        Date finishTime = vo.getFinishTime();
        String remark = vo.getRemark();
        Long  dealerId = vo.getDealerId();
//        if(startTime==null||finishTime==null){
//            throw new IllegalArgumentException("起止时间不能为空");
//        }
        // 更新node 数据
        NodeDO nodeDO = nodeMapper.selectById(vo.getNodeId());
//        nodeDO.setStartTime(startTime);
//        nodeDO.setFinishTime(finishTime);
        if(StrUtil.isNotEmpty(remark)){
            nodeDO.setRemark(remark);
        }
        nodeMapper.updateById(nodeDO);

        // 更新图片
        PicDO picDo = new PicDO();
        picDo.setHouseId(vo.getHouseId());
        picDo.setFlowId(vo.getFlowId());
        picDo.setNodeId(vo.getNodeId());
        picDo.setUploadType("0");
        picDo.setSourceType("2");
        // 保存图片文件
        picService.savePicData(picDo,vo.getFileList());


        // 判断当前任务类型 如果是补充任务 则  新增一个流转任务
        if("0".equals(vo.getTaskType())){
            // 修改任务状态
            flowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_2.getCode());
            flowTaskMapper.updateById(flowTaskDO);

            // 新增流转任务
            flowTaskDO.setId(null);
            flowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_1.getCode());
            flowTaskDO.setTaskType("1");
            if(dealerId!=null && dealerId.equals(SecurityFrameworkUtils.getLoginUserId())){
                flowTaskDO.setDealerId(dealerId);
            }

            flowTaskMapper.insert(flowTaskDO);
        }
    }


    public void saveFlowTask(Long houseId,Long flowId,NodeDO nodeDO){
        // 查询 设计流程信息
        QueryWrapper  query = new QueryWrapper();
        query.eq("id",flowId);
        FlowDO flowDO = flowMapper.selectOne(query);
        // 建立项目简介
        QueryWrapper  queryNode = new QueryWrapper();
        queryNode.eq("id",houseId);
        HouseDO houseDO = houseMapper.selectOne(queryNode);


        // 创建开工信息补充提醒
        FlowTaskDO flowTaskDO = new FlowTaskDO();
        flowTaskDO.setTaskName("任务处理");
        flowTaskDO.setHouseId(houseDO.getId());
        flowTaskDO.setProjectName(houseDO.getProjectName());
        flowTaskDO.setFlowId(flowDO.getId());
        flowTaskDO.setFlowName(flowDO.getFlowName());
        flowTaskDO.setNodeId(nodeDO.getId());
        flowTaskDO.setNodeName(nodeDO.getNodeName());

        Long dealerId = SecurityFrameworkUtils.getLoginUserId();
        String taskType = FlowTaskTypeEnum.FLOW_TASk_CD_1.getCode().toString();
        // add by czw 2023年7月14日  增加 预处理角色判断  配置预处理角色 则选择对应角色的用户 start
        String roleId = "";
        if(FlowCdEnum.FLOW_CD_0.getCode().equals(flowDO.getFlowCd())){
            // 设计流程   默认设计师
            roleId = StrUtil.isNotEmpty(nodeDO.getPreRoleId()) ?
                    nodeDO.getPreRoleId(): DesignUserRoleEnum.DESIGN.getRoleId().toString();
        }else if(FlowCdEnum.FLOW_CD_1.getCode().equals(flowDO.getFlowCd())){
            // 采购流程   默认供应商
            roleId = StrUtil.isNotEmpty(nodeDO.getPreRoleId()) ?
                    nodeDO.getPreRoleId(): DesignUserRoleEnum.SUPPLIER.getRoleId().toString();
        }else if(FlowCdEnum.FLOW_CD_2.getCode().equals(flowDO.getFlowCd())){
            // 施工流程   默认项目经理
            roleId = StrUtil.isNotEmpty(nodeDO.getPreRoleId()) ?
                    nodeDO.getPreRoleId(): DesignUserRoleEnum.PROJECT_MANAGER.getRoleId().toString() ;

        }

        String roleName  = DesignUserRoleEnum.getRoleNameByRoleId(Long.valueOf(roleId));
        if(StrUtil.isNotEmpty(roleId)){
            QueryWrapper  queryRel = new QueryWrapper();
            queryRel.eq("house_id",houseId);
            queryRel.in("status", UserRelStatusCdEnum.USER_REL_STATUS_CD_0.getCode(),
                    UserRelStatusCdEnum.USER_REL_STATUS_CD_1.getCode());
            queryRel.eq("role_id",roleId);
            List<HouseUserRelDO> houseUserRelDOList =  houseUserRelMapper.selectList(queryRel);
            if(CollUtil.isEmpty(houseUserRelDOList)){
                // 判断是否为空  为空报错
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.RELATION_ROLE_DATA_NOT_EXIST,roleName);
            }
            if(houseUserRelDOList.size()>1&&nodeDO.getDealerId()!=null){
                dealerId = nodeDO.getDealerId();
            }else{
                // TODO  这里在多个供应商的时候 会出现不知道给谁的问题 待解决！！
                dealerId = houseUserRelDOList.get(0).getUserId();
            }

        }
        // add by czw 2023年7月14日  增加 预处理角色判断  配置预处理角色 则选择对应角色的用户 end

        flowTaskDO.setDealerId(dealerId);
        // 0-补充信息 1-任务流转
        flowTaskDO.setTaskType(taskType);
        //,0-待开始1-进行中，2-已完成',
        flowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_1.getCode());
        flowTaskDO.setStartTime(new Date());
        flowTaskDO.setDeleted(false);
        flowTaskDO.setFlowCd(flowDO.getFlowCd());
        flowTaskMapper.insert(flowTaskDO);

    }
    public void getNextTaskNodeDo(Integer flowCd,Long nodeId){

        // 查询任务节点详情
        NodeDO nodeDO = nodeMapper.selectById(nodeId);
        // 查询当前流程同级所有任务节点
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("pre_id", nodeDO.getPreId());
        queryWrapper.eq("flow_id", nodeDO.getFlowId());

        List<NodeDO> nodeList = nodeMapper.selectList(queryWrapper);
        // 判断同级节点任务是否都完成
        //如果 sortId == preNodeList.length  表示 pre_id 对应的node_id 下的所有节点  全部完成
        if(String.valueOf(nodeList.size()).equals(nodeDO.getSortId())){
            if("1".equals(flowCd)){
                // 表示已完成采购流程
                nodeDO.setFinishTime(new Date());
                nodeDO.setStatusCd(NodeStatusEnum.NODE_STATUS_ENUM_2.getCode().toString());
                nodeMapper.updateById(nodeDO) ;
                // 上级节点 修改为已完成
                NodeDO preNodeDo = new NodeDO();
                preNodeDo.setId(nodeDO.getPreId());
                preNodeDo.setStatusCd(NodeStatusEnum.NODE_STATUS_ENUM_2.getCode().toString());
                preNodeDo.setFinishTime(new Date());
                nodeMapper.updateById(preNodeDo);
                return;
            }
            if(nodeDO.getPreId()!=0){
                // 都完成了  向上找父节点的同级节点
                getNextTaskNodeDo(flowCd,nodeDO.getPreId());
//                // 查询任务节点详情
//                NodeDO preNodeDO = nodeMapper.selectById(nodeDO.getPreId());
//                // 查询当前流程同级所有任务节点
//                List<NodeDO> preNodeList = nodeMapper.selectList("pre_id", nodeDO.getPreId());
            }else{
                 /*当前节点所在流程详情*/
                FlowDO flowDO = flowMapper.selectById(nodeDO.getFlowId());
                // 当前项目所有主流程 0-设计流程  1-采购流程  2-施工流程
                QueryWrapper query = new QueryWrapper();
                query.eq("house_id", flowDO.getHouseId());
                query.ne("flow_cd", flowDO.getFlowCd());
                List<FlowDO> flowDOList = flowMapper.selectList(query);
                if(FlowCdEnum.FLOW_CD_0.getCode().toString().equals(flowDO.getFlowCd().toString())){
                    // 设计流程结束 同时开启 采购流程和施工流程第一项
                    //2023年5月15日 取消开启采购流程
                    for(FlowDO flow :flowDOList){

                        getNodeFirstItemFirst(flow);
                    }
                }

            }

        }else{
            // 判断nextIds 是否有值 有值则循环开启当父节点树下指定sortId  节点

                final List<String> nexids = JSONUtil.toList(nodeDO.getNextIds(), String.class);
            if(ObjectUtil.isNotEmpty(nexids) ){
                final Long preId = nodeDO.getPreId();
                NodeDO nextIdTaskNodeDo = new NodeDO();
                for (String sortId:nexids  ) {
                    QueryWrapper queryWrapperNextId = new QueryWrapper();
                    queryWrapperNextId.eq("pre_id", preId);
                    queryWrapperNextId.eq("flow_id", nodeDO.getFlowId());
                    queryWrapperNextId.eq("sort_id", sortId);
                    queryWrapperNextId.eq("status_cd", "0");
                    final NodeDO nodeDO1 = nodeMapper.selectOne(queryWrapperNextId);
                    if(nodeDO1==null){
                        log.debug("preId："+preId +"---- sortId:"+sortId+" 已开启");
                        continue;
                    }
                    // 将指定节点  开启
                    nextIdTaskNodeDo = getNodeFirstItem(nodeDO1.getId());
                    if(nextIdTaskNodeDo==null){
                        nextIdTaskNodeDo = nodeDO1;
                    }
                    // 生成子节点的待办任务 同时将子节点  改为进行中
                    saveFlowTask(nextIdTaskNodeDo.getHouseId(),nextIdTaskNodeDo.getFlowId(),nextIdTaskNodeDo);
                    nextIdTaskNodeDo.setStartTime(new Date());
                    nextIdTaskNodeDo.setStatusCd("1");
                    nodeMapper.updateById(nextIdTaskNodeDo);

                    /*上级节点 修改为已完成*/
                    nodeDO1.setStartTime(new Date());
                    nodeDO1.setStatusCd("1");
                    nodeMapper.updateById(nodeDO1) ;
                    continue;

//                    getNextTaskNodeDo(nodeDO1.getFlowDtlCd(),nodeDO1.getId());
                }



            }else{


            // 检查开启 下一节点
            // 因为  设计流程 完成后 需要同时处理 采购流程和施工流程的首个任务节点 所以不能统一返回NodeDO 做统一处理
            // 这里直接单独处理将任务做成
            NodeDO nextTaskNodeDo = new NodeDO();
            for (NodeDO nodeDoItem:nodeList  ) {
                if(nodeDoItem.getSortId().equals(String.valueOf(Integer.valueOf(nodeDO.getSortId())+1))&& "0".equals(nodeDoItem.getStatusCd())){

                    nextTaskNodeDo = getNodeFirstItem(nodeDoItem.getId());
                    if(nextTaskNodeDo==null){
                        nextTaskNodeDo = nodeDoItem;
                    }else{
                        // 将任务父节点置为 进行中
                        nodeDoItem.setStartTime(new Date());
                        nodeDoItem.setStatusCd("1");
                        nodeMapper.updateById(nodeDoItem);
                    }
                    // 生成子节点的待办任务 同时将子节点  改为进行中
                    saveFlowTask(nextTaskNodeDo.getHouseId(),nextTaskNodeDo.getFlowId(),nextTaskNodeDo);
                    nextTaskNodeDo.setStartTime(new Date());
                    nextTaskNodeDo.setStatusCd("1");
                    nodeMapper.updateById(nextTaskNodeDo);
                    break;
                }
            }
            }
//            saveFlowTask(nextTaskNodeDo.getHouseId(),nextTaskNodeDo.getFlowId(),nextTaskNodeDo);

        }
        /*上级节点 修改为已完成*/
        nodeDO.setFinishTime(new Date());
        nodeDO.setStatusCd("2");
        nodeMapper.updateById(nodeDO) ;

    }

    public void getNodeFirstItemFirst(FlowDO flow){
        // 采购流程直接开启所有采购任务
        if("1".equals(flow.getFlowCd())){
               return;
//            QueryWrapper preNodeListQuery = new QueryWrapper();
//            preNodeListQuery.eq("flow_id",flow.getId());
//            preNodeListQuery.eq("pre_id",0);
//             List<NodeDO> preNodeList = nodeMapper.selectList(preNodeListQuery);
//            for (NodeDO nodeDo:preNodeList  ) {
//                // 将首节点置为进行中
//                nodeDo.setStartTime(new Date());
//                nodeDo.setStatusCd("1");
//                nodeMapper.updateById(nodeDo) ;
//                // 查询当前流程子节点的第一个节点 直到最后一个节点
//                // 并将每个子节点的首节点  改为进行中
//                NodeDO nodeFirstItem = getNodeFirstItem(nodeDo.getId());
//                if(nodeFirstItem==null) {
//                    nodeFirstItem =  nodeDo;
//                }
//                saveFlowTask(flow.getHouseId(),flow.getId(),nodeFirstItem);
//            }
        }else{
            // 查询所属流程中 第一个节点
            QueryWrapper preNodeQuery = new QueryWrapper();
            preNodeQuery.eq("flow_id",flow.getId());
            preNodeQuery.eq("pre_id",0);
            preNodeQuery.eq("sort_id",1);

            NodeDO nodeFirst = nodeMapper.selectOne(preNodeQuery);
            if(ObjectUtil.isNotEmpty(nodeFirst)){
                // 将首节点置为进行中
                nodeFirst.setStartTime(new Date());
                nodeFirst.setStatusCd("1");
                nodeMapper.updateById(nodeFirst) ;
                // 查询当前流程子节点的第一个节点 直到最后一个节点
                // 并将每个子节点的首节点  改为进行中
                NodeDO nodeFirstItem = getNodeFirstItem(nodeFirst.getId());
                if(nodeFirstItem==null){
                    nodeFirstItem = nodeFirst;
                }
                saveFlowTask(flow.getHouseId(),flow.getId(),nodeFirstItem);
            }else {
                // 给项目经理发送一个待办
                // 如果没有项目经理 就给 主创建人发布一个待办提醒
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.SG_FLOW_NOT_CREATE_TO);
//                throw new ServiceException(ErrorCode," 施工流程未创建，请创建后流转");
            }

        }


        // 采购发送给设计师 补充待办

        // 施工发送给项目经理补充待办

//        if("1".equals(flowDO.getFlowCd())){
//            //表示所有采购项目完成  后续可作为开关开启指定施工节点
//
//        }
//        if("2".equals(flowDO.getFlowCd())){
//            //表示施工流程所有项目完成 无需流转
//            // 发一笔系统提醒 关闭项目
//        }
    }

    public NodeDO getNodeFirstItem(Long flowId){


        QueryWrapper preNodeQuery = new QueryWrapper();
        preNodeQuery.eq("pre_id",flowId);
        preNodeQuery.eq("sort_id",1);
        preNodeQuery.eq("status_cd", "0");
        NodeDO nodeFirst = nodeMapper.selectOne(preNodeQuery);

        if(nodeFirst!=null){
            nodeFirst.setStartTime(new Date());
            nodeFirst.setStatusCd("1");
            nodeMapper.updateById(nodeFirst);
            NodeDO nodeFirstItem = getNodeFirstItem(nodeFirst.getId());
            nodeFirst.setStartTime(new Date());
            if(nodeFirstItem==null){
                // 修改每个node 状态为进行中
                nodeFirst.setStartTime(new Date());
                nodeFirst.setStatusCd("1");
                nodeMapper.updateById(nodeFirst);
                return nodeFirst;
            }else{
                NodeDO nodeFirstItem1 =   getNodeFirstItem(nodeFirstItem.getId());
                if(nodeFirstItem1==null){
                    // 修改每个node 状态为进行中
                    nodeFirstItem.setStartTime(new Date());
                    nodeFirstItem.setStatusCd("1");
                    nodeMapper.updateById(nodeFirstItem);
                    return nodeFirstItem;
                }
            }
        }

        return null;


    }

    /**
     * 回退任务
     * @param vo
     */
    @Override
    public void rollbackTask(FlowTaskBaseVO vo) {
        if(vo.getNodeId()==null){
            log.info( "由流程进展发起退回：{}",vo   );
            // 此回退由 流程发起
            vo.setNodeId(vo.getId());
        }

        // 最终任务项
        NodeDO nextTaskNodeDo = new NodeDO();
        // 根据nodeId flowCd   statusCd 查询出当前任务所属id
        NodeDO nodeDO = nodeMapper.selectById(vo.getId());
        if(!NodeStatusEnum.NODE_STATUS_ENUM_1.getCode().toString().equals(nodeDO.getStatusCd())){

            throw ServiceExceptionUtil.exception(ErrorCodeConstants.NODE_DATA_IS_UPDATE);
        }
        String isRollback = nodeDO.getIsRollback();
        if("0".equals(isRollback)){

            throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN);
//            throw new ServiceException("当前节点已回退,不允许多次回退");
        }
        // 判断
        int ptrSortId = Integer.valueOf(nodeDO.getSortId()) - 1;
        QueryWrapper<NodeDO> nodeWrapper = new QueryWrapper<NodeDO>();
        NodeDO preNodeDO = null;
        NodeDO nodeDOPre1 = null;
        NodeDO nodeDOPre2 = null;
        if(0==ptrSortId){
            log.info( "需要流转父节点上一节点最后的子任务：{}",vo   );
            // ptrSortId = 0  表示需要到父节点   查询父节点的上一节点的最后一个任务
            // 查询父任务节点
            nodeDOPre1 = nodeMapper.selectById(nodeDO.getPreId());
            log.info( "父节点：{}",nodeDOPre1  );
            //          上一节点 改为进行中   是否回退 改为是
            if("1".equals(nodeDOPre1.getIsRollback())){
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN);
//                throw new ServiceException(nodeDOPre1.getNodeName()+"上节点已有回退记录,不允许多次回退");
            }
           int sortIdPre = Integer.valueOf(nodeDOPre1.getSortId()) - 1;
            // 查询父任务节点 上一节点
            nodeWrapper.eq("flow_id", nodeDOPre1.getFlowId());
            nodeWrapper.eq("house_id", nodeDOPre1.getHouseId());
            nodeWrapper.eq("status_cd","2");
            nodeWrapper.eq("pre_id",nodeDOPre1.getPreId());
            nodeWrapper.eq("sort_id",sortIdPre);

             nodeDOPre2 = nodeMapper.selectOne(nodeWrapper);
            log.info( "父节点上一节点：{}",nodeDOPre2   );
            if("1".equals(nodeDOPre2.getIsRollback())){
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN,nodeDOPre2.getNodeName());
//                throw new ServiceException("节点已有回退记录,不允许多次回退");
            }
            nodeWrapper = new QueryWrapper<NodeDO>();
            nodeWrapper.eq("pre_id",nodeDOPre2.getId());
            nodeWrapper.eq("status_cd","2");
            // 算出 节点下有多少子节点  根据sortId 找最后一个任务
            List<NodeDO> nodeDOS = nodeMapper.selectList(nodeWrapper);
            if(CollUtil.isNotEmpty(nodeDOS)){
                for (NodeDO entity: nodeDOS  ) {
                    if(String.valueOf(nodeDOS.size()).equals(entity.getSortId())){
                        preNodeDO = entity;
                        break;
                    }
                }
            }
            nodeDOPre1.setIsRollback("1");
            nodeDOPre1.setStatusCd("0");
            nodeMapper.updateById(nodeDOPre1);

            nodeDOPre2.setIsRollback("1");
            nodeDOPre2.setStatusCd("1");
            nodeMapper.updateById(nodeDOPre2);

        }else{
            // 查询上一任务节点

            nodeWrapper.eq("flow_id", nodeDO.getFlowId());
            nodeWrapper.eq("house_id", nodeDO.getHouseId());
            nodeWrapper.eq("status_cd","2");
            nodeWrapper.eq("pre_id",nodeDO.getPreId());
            nodeWrapper.eq("sort_id",ptrSortId);
            preNodeDO = nodeMapper.selectOne(nodeWrapper);

        }

//          上一节点 改为进行中   是否回退 改为是
        if("1".equals(preNodeDO.getIsRollback())){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.EXIST_ROLLBACK_TURN_DOWN,preNodeDO.getNodeName());
//            throw new NullPointerException("上节点已有回退记录,不允许多次回退");
        }
        preNodeDO.setIsRollback("1");
        preNodeDO.setStatusCd("1");
        nodeMapper.updateById(preNodeDO);

//            上一节点任务由结束改为进行中  结束时间改为空
        FlowDO preFlowDO = flowMapper.selectById(preNodeDO.getFlowId());
        QueryWrapper<FlowTaskDO> preQueryWrapper = new QueryWrapper<FlowTaskDO>();
        preQueryWrapper.eq("status_cd","2");
        preQueryWrapper.eq("node_id",preNodeDO.getId());
        FlowTaskDO preFlowTaskDO = flowTaskMapper.selectOne(preQueryWrapper);
        preFlowTaskDO.setStatusCd(FlowTaskStatusEnum.FLOW_STATUS_ENUM_1.getCode());
        preFlowTaskDO.setFinishTime(null);
        flowTaskMapper.updateById(preFlowTaskDO);


//          当前节点 改为待开始
        nodeDO.setIsRollback("1");
        nodeDO.setStatusCd("0");
        nodeMapper.updateById(nodeDO);
//            删除当前任务
        QueryWrapper<FlowTaskDO> queryWrapper = new QueryWrapper<FlowTaskDO>();

        // 查询当前任务明细
        queryWrapper.eq("status_cd","1");
        queryWrapper.eq("node_id",nodeDO.getId());
        flowTaskMapper.delete(queryWrapper);


    }

    /**
     * @param id
     * @return
     */
    @Override
    public FlowTaskBaseVO getFlowTaskDetailById(Long id) {
        FlowTaskDO flowTaskDO = flowTaskMapper.selectById(id);
        PicDO picDO = new PicDO();
        picDO.setHouseId(flowTaskDO.getHouseId());
        picDO.setItemId(flowTaskDO.getId());
        picDO.setUploadType("0");
        picDO.setSourceType("5");
        List<PicDO> picData = picService.getPicData(picDO);
//        flowTaskDO.setF
        return null;
    }


    /**
     * 通用任务处理类
     * @param vo
     */
    @Override
    public Object dealFolwTask(CommonFlowTaskActionVo vo) throws Throwable {
//        FlowTaskBaseVO flowTask = vo.getData();
        // 根据 taskType  查询 反射类
        final FlowTaskActionDO flowTaskActionDo = flowTaskActionMapper.selectOne("task_type", vo.getTaskType());
        Class<?> aClass1 = null;
        Object invoke = null;
        try{
           aClass1 = ClassLoaderUtil.loadClass(flowTaskActionDo.getTaskAction());

//            final Method[] methods = aClass1.getMethods();
//            String methodName ="";
//            if("0".equals(vo.getDealType())){
//                methodName="confirmAction";
//            }else if("1".equals(vo.getDealType())){
//                methodName="refuseAction";
//            }else if("2".equals(vo.getDealType())){
//                methodName="viewAction";
//            }
//            Class paramType = null;
//            Class[] paramTypes = null;
//            for (Method meth:methods  ) {
//                final String name = meth.getName();
//              paramTypes = meth.getParameterTypes();
//                paramType = paramTypes[0];
//                if(methodName.equals(name)){
//                    break;
//                }
//            }

            Method method = null;
            switch (vo.getDealType()){
                case "0":
                    //                confirmAction  同意流转
                    method  = aClass1.getMethod("confirmAction", Object.class);
                    break;
                case "1":
                    //                refuseAction   拒绝回退
                    method  = aClass1.getMethod("refuseAction", Object.class);

                    break;
                case "2":
                    //                viewAction   查看
                    method  = aClass1.getMethod("viewAction",Object.class);

                    break;
                case "3":
                    // 任务日志登记
                    method  = aClass1.getMethod("replenishTask",Object.class);
                    break;
                case "4":
                    break;

                default:
                    break;

            }

        // 调用反射方法
//            使用SpringContext上下文获取对应Bean，从而避免注解失效。
            invoke  = method.invoke(SpringUtil.getBean(aClass1),vo.getData());
        }catch ( IllegalAccessException | NoSuchMethodException e){
           e.printStackTrace();

        }catch (InvocationTargetException e) {
            // 抛出代码内 业务异常
            throw  e.getTargetException();

        }

        return invoke;

    }

    /**
     * 查询项目内个人 任务数量
     *
     * @param houseId 项目id
     * @return count
     */
    @Override
    public int getTaskCount(Long houseId) {
        QueryWrapper  queryWrapper = new QueryWrapper();
        queryWrapper.eq("house_id",houseId);
        queryWrapper.eq("dealer_id" ,SecurityFrameworkUtils.getLoginUserId());
        // 进行中
        queryWrapper.eq("status_cd","1");

        return Math.toIntExact(flowTaskMapper.selectCount(queryWrapper));
    }

    /**
     * 查询项目内个人 任务数量
     *
     * @param ids@return count
     */
    @Override
    public List<FlowTaskCountDO> getTaskCountList(Collection<Long> ids) {


        return flowTaskMapper.getTaskCountList(ids,SecurityFrameworkUtils.getLoginUserId());
    }
    @Override
    public void createUserRelFlowTask(Long houseId, String projectName, Long userId, Long roleId) {
        createHouseUserRelFlowTask( houseId,  projectName,  userId,  roleId,  UserRelStatusCdEnum.USER_REL_STATUS_CD_0.getCode());
    }

    /**
     * 启动项目并创建关联项目任务（创建前判断好友状态是否正常
     * 正常则 任务状态正常   待处理 则任务状态为待开始  等待好友通过后 启动任务）
     *
     * @author Annie
     * @time 2023/11/7 22:54
     */
    @Override
    public void createHouseUserRelFlowTask(Long houseId, String projectName, Long userId, Long roleId, Integer statusCd) {
        final Long loginUserId = SecurityFrameworkUtils.getLoginUserId();

        if(String.valueOf(loginUserId).equals(String.valueOf(userId))){
            log.debug("处理人与登录人相同 则不建立申请任务");
            return;
        }

        final AdminUserDO user = userService.getUser(loginUserId);
        FlowTaskDO flowTaskDO = new FlowTaskDO();
        flowTaskDO.setTaskName("项目关联申请");
        flowTaskDO.setHouseId(houseId);
        flowTaskDO.setProjectName(projectName);
        flowTaskDO.setDealerId(userId);
        // 0-补充信息 1-任务流转 2-项目关联申请
        flowTaskDO.setTaskType(FlowTaskTypeEnum.FLOW_TASk_CD_2.getCode().toString());
        //1-进行中，2-已完成',
        if(statusCd==null){
            statusCd = FlowTaskStatusEnum.FLOW_STATUS_ENUM_0.getCode();
        }
        flowTaskDO.setStatusCd(statusCd);
        flowTaskDO.setStartTime(new Date());
        flowTaskDO.setDeleted(false);
        flowTaskDO.setFlowCd(Integer.valueOf(Math.toIntExact(roleId)));  // 暂存角色字段
        String remark = user.getNickname()+"  邀请你加入 \n【 " +projectName+" 】 项目";
        flowTaskDO.setRemark(remark);
        flowTaskDO.setCreator(loginUserId.toString());
        flowTaskMapper.insert(flowTaskDO);
    }



    /**
     * 删除待处理的待办任务
     *
     * @param houseId
     * @param userId
     * @param[1] houseId
     * @param[2] userId
     */
    @Override
    public void deleteFlowTaskByHouseIdAndUserId(Long houseId, Set<Long> userId, Integer taskType) {
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("house_id",houseId);
        queryWrapper.in("dealer_id",userId);
        queryWrapper.eq("task_type",taskType);
        queryWrapper.in("status_cd",FlowStatusEnum.FLOW_STATUS_ENUM_0.getCode(),FlowStatusEnum.FLOW_STATUS_ENUM_1.getCode());
        flowTaskMapper.delete(queryWrapper);
    }


}
